(defgroup epub nil
  "convert the txt and other types of files to html and generate a epub archive file"
  :group 'tool)

(defcustom epub-source-directory "."
  "the dir which contains all archive files"
  :type 'string
  :group 'epub)

(defcustom epub-title "epub"
  "the epub filename"
  :type 'string
  :group 'epub)

(defcustom epub-template-directory "~/.emacs.d/epub-template/"
  "the epub template directory"
  :type 'string
  :group 'epub)

(defcustom epub-cover (concat epub-template-directory "cover.jpeg")
  "the epub cover"
  :type 'string
  :group 'epub)

(defcustom epub-upper 20
  "the The maximum number files which a epub file contains"
  :type 'integer
  :group 'epub)

(defun files-in-below-directory (directory)
  (interactive "Dsource directory: ")
  (let (el-files-list
	(current-directory-list
	 (directory-files-and-attributes directory t)))
    ;; while we are in the current directory
    (while current-directory-list
      ;; check whether filename is that of a directory
      (if (eq t (car (cdr (car current-directory-list))))
	  ;; decide whether to skip or recurse
	  (if
	      (equal "."
		     (substring (car (car current-directory-list)) -1))
	      ;; then do nothing since filename is that of
	      ;;   current directory or parent, "." or ".."
	      ()
	    ;; else descend into the directory and repeat the process
	    (setq el-files-list
		  (append
		   (files-in-below-directory
		    (car (car current-directory-list)))
		   el-files-list)))
	(setq el-files-list
	      (cons  (car (car current-directory-list)) el-files-list)))
      ;; move to the next filename in the list; this also
      ;; shortens the list so the while loop eventually comes to an end
      (setq current-directory-list (cdr current-directory-list)))
    ;; return the filenames
    el-files-list))

(defun generate-title ()
  "return the proper epub title"
  (concat epub-title (if (> epub-cnt 0)  (format "-%s" epub-cnt))))

(defun make-opf()
  "make the 'content.opf' file"
  (with-temp-file (expand-file-name "content.opf" oebps-directory)
    (insert-file-contents (concat epub-template-directory "/content.opf"))
    (replace-regexp "\\B@time\\>" (format-time-string "%Y-%m-%d") nil (point-min) (point-max))
    (replace-regexp "\\B@title\\>" (generate-title) nil (point-min) (point-max))
    (let ((content)
	  (contentref))
      (dolist (id-cap id-caption-array)
	(setq content (concat content 
			      (format "<item id=\"%s\" media-type=\"application/xhtml+xml\" href=\"%s\"/>\n" (first id-cap) (second id-cap))))
	(setq contentref (concat contentref (format "<itemref idref=\"%s\"/>\n" (first id-cap)))))
      (replace-regexp "\\B@content\\>" content nil (point-min) (point-max))
      (replace-regexp "\\B@contentref\\>" contentref nil (point-min) (point-max)))))

(defun make-toc ()
  "make the toc.ncx file"
  (with-temp-file (expand-file-name "toc.ncx" oebps-directory)
    (insert-file-contents (concat epub-template-directory "/toc.ncx"))
    (let ((navPoint)
	  (cnt 0))
      (dolist (id-cap id-caption-array)
	(setq navPoint (concat navPoint 
			       "<navPoint id=\"" (first id-cap)  "\" playOrder=\"" (int-to-string (incf cnt)) "\">\n"
			       "<navLabel><text>" (third id-cap) "</text></navLabel>\n"
			       "<content src=\""  (second id-cap) "\"/>\n"
			       "</navPoint>\n")))
      (replace-regexp "\\B@navPoint\\>" navPoint nil (point-min) (point-max)))))

(defun make-cover ()
  "generate the cover file"
  (with-temp-file (expand-file-name "coverpage.xhtml" oebps-directory)
    (insert-file-contents (expand-file-name "coverpage.xhtml" epub-template-directory))
    (replace-regexp "\\B@title\\>" (generate-title) nil (point-min) (point-max))))


(defun txt2html (file html-file)
  "convert a txt file to html file"
  (let ((coding-system-for-write 'utf-8-emacs))
  (with-temp-file html-file
    (insert-file-contents (concat epub-template-directory "/book.html"))
    (replace-regexp "\\B@title\\>" (file-name-sans-extension (file-name-nondirectory file)) nil (point-min) (point-max))
    (replace-regexp "\\B@placeholder\\>" "" nil (point-min) (point-max))
    (let* ((beg (point))
	   (end (+ beg (second (insert-file-contents file)))))
      (replace-regexp ".*" "<p>\\&</p>" nil beg end))
    ;; (set-buffer-file-coding-system (quote utf-8) nil)
    ;; (save-current-buffer)
    )))

(defun make-one-epub ()
  "generate one epub file by epub-upper."
  "generate files"
  (make-cover)
  (make-opf)
  (make-toc)
  (let ((original-dir (expand-file-name "."))
	(epub-name (concat target-directory "../" epub-title ".epub ")))
    (cd target-directory)
    (let ((name (concat "../" (generate-title) ".epub")))
      (shell-command (concat "zip -0Xq " name " mimetype"))
      (shell-command (concat "zip -Xr9Dq " name " *"))
      (message (expand-file-name name target-directory)))
    (cd original-dir))
  (delete-windows-on "*Messages*"))

(defun get-args ()
  "get source and target directory."
  (setq epub-source-directory 
	(expand-file-name 
	 (read-directory-name 
	  (concat "source directory[" epub-source-directory "]: ") "." epub-source-directory t)))
  
  (setq target-directory (expand-file-name "./epub" (expand-file-name (concat epub-source-directory "/.."))))
  (setq  oebps-directory (concat target-directory "/OEBPS" ))
  "get title of epub file"
  (setq epub-title 
	(read-string (format "title[%s]: " epub-title) epub-title))

  "get the cover of epub file"
  (setq epub-cover (expand-file-name 
		    (read-file-name (format"cover[%s]: " epub-cover) nil epub-cover  t))))

(defun make-epub ()
  "make the $epub-title.epub file"
  (interactive)
  "generate epub files"
  (let ((file-cnt 0)
	(epub-cnt 0)
	(id-caption-array)
	(target-directory)
	(oebps-directory))

    (get-args)
    "make new target dir"
    (dolist (dir (list target-directory oebps-directory))
      (if (file-directory-p dir)
	  (delete-directory dir t))
      (mkdir dir))

    "copy template files"
    (copy-file (expand-file-name "mimetype"  epub-template-directory) target-directory t)
    (copy-directory (expand-file-name "META-INF" epub-template-directory ) target-directory t)
    (copy-file epub-cover (expand-file-name "cover.jpeg" oebps-directory) t)
    (copy-file (concat epub-template-directory "/main.css") (expand-file-name "main.css" oebps-directory) t)

    (buffer-disable-undo)
    (dolist (file (files-in-below-directory epub-source-directory))
      (let* ((extension (file-name-extension file))
	     (id (format "book-%s" (incf file-cnt)))
	     (html-name (concat id ".html")))
	(if (or (equal extension "html")
		(equal extension "htm"))
	    (copy-file file (expand-file-name html-name oebps-directory) t)
	  (txt2html file  (expand-file-name html-name oebps-directory)))
	(add-to-list 'id-caption-array (list id html-name (file-name-sans-extension (file-name-nondirectory file)))))
      (if (< file-cnt epub-upper)
	  ()
	(incf epub-cnt)
	(make-one-epub)
	(delete-directory oebps-directory t)
	(mkdir oebps-directory)
	(setq file-cnt 0)
	(setq id-caption-array nil)))
    (if (= file-cnt 0)
	()
      (if (> epub-cnt 0) (incf epub-cnt))
      (make-one-epub))
    (buffer-enable-undo)
    (delete-directory target-directory t))
  
  (message "completed."))

(provide 'epub)

;;; epub ends here.









